﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows.Forms;
using System.Xml.Serialization;
using CalcSharp.Core.PackageMan;
using CalcSharp.Core;
using System.Text;

namespace pkgman
{
    public partial class updMain : Form
    {
        private List<string> temps;
        private string[] installed; //telepített fájlok
        private string[] threadpars;
        private Thread back;
        public delegate void UpdateProgressCall(string lbtext);
        public delegate void AfterInstallCall(string msg);
        public delegate void DloadProgressCall(long len, long pos);
        string pkgdir;

        public updMain()
        {
            InitializeComponent();
            this.statusinfo.Text = "";
            this.temps = new List<string>();
            this.pkgdir = Path.GetDirectoryName(Application.ExecutablePath) + "\\pkgman";
            this.threadpars = new string[2];
            this.readInstalled();
        }

        #region Code

        private void ShowError(CSException ex)
        {
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        private Package Item2Package(ListViewItem selected)
        {
            XmlSerializer xs = new XmlSerializer(typeof(Package));
            FileStream inp;
            Package P;
            string appdir = Path.GetDirectoryName(Application.ExecutablePath);
            foreach (string pkg in this.installed)
            {
                inp = File.OpenRead(pkg);
                P = (Package)xs.Deserialize(inp);
                inp.Close();
                if (P.name == selected.Text) return P;
            }
            return null;
        }

        private string addTempfile()
        {
            string tmp = Path.GetTempFileName();
            this.temps.Add(tmp);
            return tmp;
        }

        private void tempCleanup()
        {
            if (this.temps.Count > 0)
            {
                foreach (string tmp in temps) File.Delete(tmp);
            }
            this.temps.Clear();
        }

        private void readInstalled()
        {
            if (!Directory.Exists(this.pkgdir)) Directory.CreateDirectory(this.pkgdir);
            this.installed = Directory.GetFiles(this.pkgdir, "*.xml");
            this.lv_local.Items.Clear();
            this.icons_local.Images.Clear();
            ListViewItem it;
            XmlSerializer XS = new XmlSerializer(typeof(Package));
            FileStream inp;
            Package P;
            int i = 0;
            foreach (string pkg in installed)
            {
                try
                {
                    inp = File.OpenRead(pkg);
                    P = (Package)XS.Deserialize(inp);
                    inp.Close();
                    it = new ListViewItem();
                    it.Text = P.name;
                    it.Name = i.ToString();
                    it.SubItems.Add(P.Description);
                    it.SubItems.Add(P.version.ToString());
                    icons_local.Images.Add(P.icon.decode());
                    it.ImageIndex = i;
                    i++;
                    this.lv_local.Items.Add(it);
                }
                catch { ; }
            }
        }


        private void InstallPackage(string pkgpath)
        {
            Package Pi = ZipPack.getpackageinfo(pkgpath);
            string xml;
            bool readytoinstall = false;
            if (!string.IsNullOrEmpty(Pi.license))
            {
                pkgLicenseFrm lic = new pkgLicenseFrm();
                lic.Licensetxt = Pi.license;
                if (lic.ShowDialog() == DialogResult.Yes) readytoinstall = true;
            }
            else readytoinstall = true;

            if (readytoinstall)
            {
                XmlSerializer xs = new XmlSerializer(typeof(Package));
                xml = Pi.name + ".xml";
                FileStream dest = File.Create(this.pkgdir + "\\" + xml);
                xs.Serialize(dest, Pi);
                dest.Close();
                try
                {
                    ZipPack.unpack(pkgpath, Path.GetDirectoryName(Application.ExecutablePath));
                }
                catch (CSException ex) { ShowError(ex); }
            }
        }

        private void UninstallPackage(string pkginfo)
        {
            XmlSerializer xs = new XmlSerializer(typeof(Package));
            StringBuilder failed = new StringBuilder();
            string appdir = Path.GetDirectoryName(Application.ExecutablePath);
            FileStream input = File.OpenRead(pkginfo);
            Package Pi = (Package)xs.Deserialize(input);
            input.Close();
            foreach (string file in Pi.files)
            {
                try
                {
                    File.Delete(appdir + "\\" + file);
                }
                catch
                {
                    failed.Append(file);
                    failed.Append("\r\n");
                }
            }
            File.Delete(pkginfo);
            if (failed.Length > 0)
            {
                MessageBox.Show("Failed to remove the following files:\r\n" + failed.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /*private void ReadAvailable()
        {
            XmlSerializer XS = new XmlSerializer(typeof(Package[]));
            FileStream inp;
            Package[] available;
            ListViewItem it;
            int i = 0;
            this.lv_remote.Items.Clear();
            try
            {
                inp = File.OpenRead(this.threadpars[1]);
                available = (Package[])XS.Deserialize(inp);
                inp.Close();
                foreach (Package pkg in available)
                {
                    it = new ListViewItem();
                    it.Text = pkg.name;
                    it.Name = i.ToString();
                    it.SubItems[0].Text = pkg.Description;
                    it.SubItems.Add(pkg.version.ToString());
                    icons_remote.Images.Add(pkg.icon.decode());
                    it.ImageIndex = i;
                    i++;
                    this.lv_remote.Items.Add(it);
                }
            }
            catch
            {
                ;
            }
        }*/
        #endregion

        #region UI
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void updMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            tempCleanup();
        }

        private void refreshPackageListToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.threadpars = new string[2];

            this.threadpars[0] = @"http://127.0.0.1/pkglist.xml";
            this.threadpars[1] = this.addTempfile();
            back = new Thread(Download);
            back.Start();
        }

        private Package file2pack(string f)
        {
            XmlSerializer xs = new XmlSerializer(typeof(Package));
            FileStream fi = File.OpenRead(f);
            Package ret = (Package)xs.Deserialize(fi);
            fi.Close();
            return ret;
        }

        private void installAPackageToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool caninstall = false;
            if (open_pkgdlg.ShowDialog() == DialogResult.OK)
            {
                if (back != null)
                {
                    if (!back.IsAlive) caninstall = true;
                    else MessageBox.Show("Another Operation is runing. Please wait");
                }
                else caninstall = true;

                if (caninstall)
                {
                    
                    Package inf = ZipPack.getpackageinfo(open_pkgdlg.FileName);
                    Package tmp;
                    int i;
                    bool caninstall2 = true;
                    StringBuilder err = new StringBuilder();
                    if (inf.requires != null)
                    {
                        if (inf.requires.Length > 0)
                        {
                            bool[] depsok = new bool[inf.requires.Length];
                            for (i = 0; i < inf.requires.Length; i++)  // (DependentPackage dp in inf.requires)
                            {
                                foreach (string pkg in this.installed)
                                {
                                    tmp = file2pack(pkg);
                                    if (inf.requires[i].name == tmp.name && inf.requires[i].version == tmp.version)
                                    {
                                        depsok[i] = true;
                                        break;
                                    }
                                }
                            }
                            for (i = 0; i < depsok.Length; i++)
                            {
                                if (depsok[i] == false)
                                {
                                    caninstall2 = false;
                                    err.Append(inf.requires[i].name + " v. ");
                                    err.Append(inf.requires[i].version.ToString());
                                    err.Append("\r\n");
                                }
                            }
                            if (!caninstall2)
                            {
                                MessageBox.Show("Can't install package, because dependencies are missing:\r\n" + err.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return;
                            }
                        }
                    }
                    if (MessageBox.Show("Intall this Package ?\n" + inf.name + " " + inf.version.ToString() + "\n" + inf.Description, "Question", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        threadpars = new string[1];
                        threadpars[0] = open_pkgdlg.FileName;
                        back = new Thread(Install);
                        back.Start();
                    }
                }
            }
        }

        private void uninstallToolStripMenuItem_Click(object sender, EventArgs e)
        {
            bool caninstall = false;
            if (back != null)
            {
                if (!back.IsAlive) caninstall = true;
                else MessageBox.Show("Another Operation is runing. Please wait");
            }
            else caninstall = true;
            if (caninstall)
            {
                threadpars = new string[1];
                threadpars[0] = this.pkgdir+"\\"+this.lv_local.SelectedItems[0].Text + ".xml";
                back = new Thread(Uninstall);
                back.Start();
            }

        }

        private void lv_local_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this.lv_local.SelectedItems.Count > 0) this.selectedToolStripMenuItem.Enabled = true;
            else this.selectedToolStripMenuItem.Enabled = false;
        }
        
        private void viewInformationToolStripMenuItem_Click(object sender, EventArgs e)
        {
            pkg_inform inf = new pkg_inform(this.Item2Package(this.lv_local.SelectedItems[0]));
            inf.Show();
        }
        #endregion


        #region threading
        public void UpdateProgress(string lbtext)
        {
            this.statusinfo.Text = lbtext;
            if (this.Animtimer.Enabled)
            {
                this.Animtimer.Enabled = false;
                this.pbProgress.Value = 0;
            }
            else
            {
                this.pbProgress.Value = 0;
                this.Animtimer.Enabled = true;
            }
        }

        public void AfterInstall(string msg)
        {
            this.readInstalled();
            MessageBox.Show(msg, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void Animtimer_Tick(object sender, EventArgs e)
        {
            if (this.pbProgress.Value >= 100) pbProgress.Value = 0;
            pbProgress.Value += 10;
        }

        private void Install()
        {
            this.Invoke(new UpdateProgressCall(UpdateProgress), new object[] { "Installing Package..." });
            this.InstallPackage(threadpars[0]);
            this.Invoke(new UpdateProgressCall(UpdateProgress), new object[] { "" });
            this.Invoke(new AfterInstallCall(AfterInstall), new object[] { "Package installed" });
        }

        private void Uninstall()
        {
            this.Invoke(new UpdateProgressCall(UpdateProgress), new object[] { "Uninstalling Package..." });
            this.UninstallPackage(threadpars[0]);
            this.Invoke(new UpdateProgressCall(UpdateProgress), new object[] { "" });
            this.Invoke(new AfterInstallCall(AfterInstall), new object[] { "Package uninstalled" });

        }

        #endregion

    }
}
